/*
 * @Author: fuhongliang-TSJ hongliang.fu@4d-bios.com
 * @Date: 2025-09-19 15:56:04
 * @LastEditTime: 2025-09-30 16:41:02
 * @LastEditors: fuhongliang-TSJ hongliang.fu@4d-bios.com
 * @Description: 
 * @FilePath: \lc_-esp32_-s3\main\lc\desktop_weather\desktop_weather.c
 * 立创实战派ESP32-S3开发板
 * Copyright (c) 2025 by 4D Bios, All Rights Reserved. 
 */

#include <math.h>
#include <time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "blufi.h"
#include "sntp.h"
#include "rng.h"
#include "sensor_task.h"
#include "desktop_weather.h"
#include "he_feng_weather.h"

static const char *TAG = "Desktop Weather";

static EventGroupHandle_t desktop_weather_event_group;

char qwnow_text[32]; // 实时天气状态

int temp_value, humi_value; // 室内实时温湿度值

time_t now;
struct tm timeinfo;

extern EventBits_t  blufi_event_bit;  
extern EventBits_t  wifi_event_bit;
extern qweather_data_t st_qweather_data;  //和风天气数据

extern lv_obj_t *gif_taikong;
extern lv_obj_t *label_wifi_connect;
extern lv_obj_t *label_sntp;
extern lv_obj_t *label_weather;
extern lv_obj_t *label_date;
extern lv_obj_t *label_time;
extern lv_obj_t *label_week;
extern lv_obj_t *label_sun;
extern lv_obj_t *label_in_door_temp;
extern lv_obj_t *label_in_door_humi;
extern lv_obj_t *label_weather_temp;
extern lv_obj_t *label_weather_text;
extern lv_obj_t *label_out_door_temp;
extern lv_obj_t *label_out_door_humi;
extern lv_obj_t *label_in_door_temp;
extern lv_obj_t *label_in_door_humi;
extern lv_obj_t *label_wifi_icon;

/**
 * @description: 获取温湿度
 * @return {*}
 */
void get_temp_humi(void)
{
    temp_value = round(get_chip_temperature());
    humi_value = rng_get_random_range(76, 81);    //76-81随机数，虚拟湿度值
}

/**
 * @description: 获取系统时间
 * @return {*}
 */
void get_time(void)
{
    // 获取系统时间
    time(&now);
    localtime_r(&now, &timeinfo);
}

// 主界面各值更新函数
void value_update_cb(lv_timer_t * timer)
{
    lvgl_port_lock(0);

    // 更新日期 星期 时分秒
    get_time();
    lv_label_set_text_fmt(label_date, "%04d年%02d月%02d日", timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday);
    lv_label_set_text_fmt(label_time, "%02d:%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
    lv_week_show();

    // WIFI图标处理
    if (wifi_event_bit == WIFI_CONNECTED_BIT)
    {
        lv_label_set_text(label_wifi_icon, LV_SYMBOL_WIFI);
    }
    else if (wifi_event_bit == WIFI_FAIL_BIT)
    {
        if ( (timeinfo.tm_sec % 2 == 0))
        {
            lv_label_set_text(label_wifi_icon, LV_SYMBOL_WIFI);
        }
        else if  (timeinfo.tm_sec % 2 == 1)
        {
            lv_label_set_text(label_wifi_icon, "");
        }
    }

    // 日出日落时间交替显示 每隔5秒切换   温湿度每隔10秒切换
    if (timeinfo.tm_sec % 10 == 0)
    {
        lv_label_set_text_fmt(label_sun, "日落 %s", st_qweather_data.daily_sun_set);

        get_temp_humi();
        lv_label_set_text_fmt(label_in_door_temp, "%02d℃", temp_value);
        lv_label_set_text_fmt(label_in_door_humi, "%d%%", humi_value);
    }
    else if (timeinfo.tm_sec % 10 == 5)
    {
        lv_label_set_text_fmt(label_sun, "日出 %s", st_qweather_data.daily_sun_rise);
    }

    // 更新实时天气
    if(st_qweather_data.now_update_flag == 1)
    {
        st_qweather_data.now_update_flag = 0;
        lv_qweather_icon_show(st_qweather_data.now_icon); // 更新天气图标
        lv_label_set_text_fmt(label_weather_text, "%s", qwnow_text); // 更新天气情况文字描述
        lv_label_set_text_fmt(label_out_door_temp, "%d℃", st_qweather_data.now_temp); // 更新室外温度
        lv_label_set_text_fmt(label_out_door_humi, "%d%%", st_qweather_data.now_humi); // 更新室外湿度
    }
    // 更新空气质量
    if(st_qweather_data.air_quality_update_flag ==1)
    {
        st_qweather_data.air_quality_update_flag = 0;
        lv_qair_level_show(st_qweather_data.air_quality_level);
    }
    // 更新每日天气
    if(st_qweather_data.daily_update_flag == 1)
    {
        st_qweather_data.daily_update_flag = 0;
        lv_label_set_text_fmt(label_weather_temp, "%d~%d℃", st_qweather_data.daily_temp_min, st_qweather_data.daily_temp_max); // 温度范围
    }

    lvgl_port_unlock();
}

/**
 * @description: 主界面任务
 * @param {void} *para
 * @return {*}
 */
void main_page_task(void *para)
{
    int tm_cnt1 = 0;
    int tm_cnt2 = 0;

    ESP_LOGI(TAG, "%s", "Main Page Task Created!");

    xEventGroupWaitBits(desktop_weather_event_group, WIFI_GET_WEATHER_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
    ESP_LOGI(TAG, "%s", "Waited WIFI_GET_WEATHER_BIT!");

    get_temp_humi();

    get_time();

    desktop_weather_gui_main_page();

    st_qweather_data.daily_update_flag = 0;
    st_qweather_data.now_update_flag = 0;
    st_qweather_data.air_quality_update_flag = 0;

    lv_timer_create(value_update_cb, 1000, NULL);  // 创建一个lv_timer 每秒更新一次数据

    while(1)
    {
        tm_cnt1++;
        if (tm_cnt1 > 1800) // 30分钟更新一次实时天气和实时空气质量
        {
            tm_cnt1 = 0; // 计数清零
            
            get_now_weather();  // 获取实时天气信息
            get_air_quality();  // 获取实时空气质量
            tm_cnt2++;
            if (tm_cnt2 > 1) // 60分钟更新一次每日天气
            {
                tm_cnt2 = 0;
                get_daily_weather(); // 获取每日天气信息
            }
            
            printf("weather update time:%02d:%02d:%02d\n", timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
        }
        
        vTaskDelay(pdMS_TO_TICKS(1000));
    }

    vTaskDelete(NULL);
}

/**
 * @description: 获取天气信息任务
 * @param {void} *para
 * @return {*}
 */
static void get_weather_task(void *para)
{
    ESP_LOGI(TAG, "%s", "Get Weather Task Created!");

    xEventGroupWaitBits(desktop_weather_event_group, WIFI_GET_SNTP_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
    ESP_LOGI(TAG, "%s", "Waited WIFI_GET_SNTP_BIT!");

    lvgl_port_lock(0);
    lv_label_set_text(label_weather, "正在获取天气信息");
    lv_obj_align_to(label_weather, label_sntp, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
    lvgl_port_unlock();

    vTaskDelay(pdMS_TO_TICKS(1000));
    
    get_daily_weather();
    get_now_weather();
    get_air_quality();
    get_air_quality_by_new_api();
    
    while(1)
    {
        vTaskDelay(pdMS_TO_TICKS(1000));
        if (st_qweather_data.daily_update_flag != 1)
        {
            ESP_LOGI(TAG, "%s", "Get 3 Daily Weather Data Fail!");
            continue ;
        }

        if (st_qweather_data.now_update_flag != 1)
        {
            ESP_LOGI(TAG, "%s", "Get Now Weather Data Fail!");
            continue ;
        }

        if (st_qweather_data.air_quality_update_flag != 1)
        {
            ESP_LOGI(TAG, "%s", "Get Air Quality Weather Data Fail!");
            continue ;
        }

        lvgl_port_lock(0);
        lv_label_set_text(label_weather, "√ 天气信息获取成功");
        lv_obj_align_to(label_weather, label_sntp, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
        lvgl_port_unlock();
        break;
    }

    ESP_LOGI(TAG, "%s", "Get Weather Task Over!");
    xEventGroupSetBits(desktop_weather_event_group, WIFI_GET_WEATHER_BIT);
    
    vTaskDelete(NULL);
}

/**
 * @description: 获取NTP时间任务
 * @param {void} *para
 * @return {*}
 */
static void get_time_task(void *para)
{
    int retry = 0;
    const int retry_count = 6;

    ESP_LOGI(TAG, "%s", "Get Time Task Created!");

    xEventGroupWaitBits(desktop_weather_event_group, WIFI_GET_CONNECTED_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
    ESP_LOGI(TAG, "%s", " Waited WIFI_GET_CONNECTED_BIT!");

    sntp_task_init();

    lvgl_port_lock(0);
    lv_label_set_text(label_sntp, "正在获取网络时间");
    lv_obj_align_to(label_sntp, label_wifi_connect, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
    lvgl_port_unlock();

    while((get_sntp_sync_status() == SNTP_SYNC_STATUS_FAIL) && (++retry < retry_count))
    {
        ESP_LOGI(TAG, "Get Time Task Get Sntp Status :%d", get_sntp_sync_status());
        vTaskDelay(pdMS_TO_TICKS(1000));
    }

    if (retry > 5)
    {
        esp_restart(); // 没有获取到时间的话 重启ESP32
    }

    lvgl_port_lock(0);
    lv_label_set_text(label_sntp, "√ 网络时间获取成功");
    lv_obj_align_to(label_sntp, label_wifi_connect, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
    lvgl_port_unlock();

    ESP_LOGI(TAG, "%s", "Get Time Task Over!");
    xEventGroupSetBits(desktop_weather_event_group, WIFI_GET_SNTP_BIT);
    
    vTaskDelete(NULL);
}

/**
 * @description: wifi连接任务
 * @param {void} *para
 * @return {*}
 */
static void wait_wifi_connect_task(void *para)
{
    ESP_LOGI(TAG, "%s", "Wait Wifi Connect Task Created!");
    vTaskDelay(pdMS_TO_TICKS(2000));
    while(1)
    {
        vTaskDelay(pdMS_TO_TICKS(1000));
        if (wifi_event_bit == WIFI_FAIL_BIT)
        {
            if ((blufi_event_bit == BLUFI_NET_CONFIG_BIT_STARTUP) || (blufi_event_bit == BLUFI_NET_CONFIG_BIT_CONFIGING))
            {
                lvgl_port_lock(0);
                lv_label_set_text(label_wifi_connect, "正在蓝牙配网");
                lv_obj_align_to(label_wifi_connect, gif_taikong, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
                lvgl_port_unlock();
            }
            else
            {
                lvgl_port_lock(0);
                lv_label_set_text(label_wifi_connect, "请长按配网按键三秒蓝牙配网");
                lv_obj_align_to(label_wifi_connect, gif_taikong, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
                lvgl_port_unlock();
            }
        }
        else if (wifi_event_bit == WIFI_CONNECTED_BIT)
        {
            lvgl_port_lock(0);
            lv_label_set_text(label_wifi_connect, "√ WiFi连接成功");
            lv_obj_align_to(label_wifi_connect, gif_taikong, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
            lvgl_port_unlock();

            xEventGroupSetBits(desktop_weather_event_group, WIFI_GET_CONNECTED_BIT);
            break;  
        }       
    }
    ESP_LOGI(TAG, "%s", "Wait Wifi Connect Task Over!");
    vTaskDelete(NULL);
}

/**
 * @description: 桌面天气程序
 * @return {*}
 */
void desktop_weather(void)
{
    desktop_weather_event_group = xEventGroupCreate();
    if (desktop_weather_event_group == NULL)
    {
        ESP_LOGE(TAG, "%s", "Desktop Weather Event Group Create Failure!");
    }

    desktop_weather_gui_start();
    xTaskCreate(wait_wifi_connect_task, "wait_wifi_connect_task", 4 * 1024, NULL, 5, NULL);  // 一次性任务   连接WIFI
    xTaskCreate(get_time_task, "get_time_task", 4 * 1024, NULL, 5, NULL);                    // 一次性任务   获取网络时间
    xTaskCreate(get_weather_task, "get_weather_task", 8 * 1024, NULL, 5, NULL);              // 一次性任务   获取天气信息
    xTaskCreate(main_page_task, "main_page_task", 8 * 1024, NULL, 5, NULL);                  // 一次性任务   获取天气信息
}